package com.interview.processor;


import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.tree.JCTree;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.Set;

@SupportedAnnotationTypes("com.interview.processor.RestCode")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class RestCodeProcessor extends AbstractProcessor {

	@Override
	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

		if (!roundEnv.processingOver()) {
			//简单向控制台输出消息
			processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING, "开始生成类123!");
			try {

				Set<? extends Element> serialSet = roundEnv.getElementsAnnotatedWith(RestCode.class);
				JavacTrees tree = JavacTrees.instance(processingEnv);
				for (Element element : serialSet) {
					if (!(element instanceof Symbol.ClassSymbol)) {
						continue;
					}

					JCTree.JCClassDecl classDecl = (JCTree.JCClassDecl) tree.getTree(element);
					processingEnv.getMessager()
							.printMessage(Diagnostic.Kind.MANDATORY_WARNING, "find " + classDecl.getSimpleName());

					//得到类名
					String classFullName = ((Symbol.ClassSymbol) element).getQualifiedName().toString();
					//目标类名
					String targetFullClassName = classFullName + "Controller";
					String packageName = targetFullClassName.substring(0, targetFullClassName.lastIndexOf('.'));

					String serviceName = classDecl.getSimpleName().toString();
					String restName = serviceName + "Controller";

					JavaFileObject builderFile = processingEnv.getFiler().createSourceFile(targetFullClassName);

					StringBuilder content = new StringBuilder(" //代码 \n");
					content.append("package ").append(packageName).append(";\n");
					content.append("import org.springframework.web.bind.annotation.RequestMapping;\n");
					content.append("import ").append(classFullName).append(";\n");
					content.append("import org.springframework.beans.factory.annotation.Autowired;\n");
					content.append("import org.springframework.web.bind.annotation.RestController;\n");
					content.append("@RestController").append("\n");
					content.append("public class ").append(restName).append("{\n");
					content.append("@Autowired ").append(serviceName).append(" service;\n");
					for (JCTree jcTree : classDecl.defs) {
						if (jcTree instanceof JCTree.JCMethodDecl) {
							JCTree.JCMethodDecl methodDecl = (JCTree.JCMethodDecl) jcTree;
							String methodName = methodDecl.name.toString();
							// 如果是构造方法
							if ("<init>".equals(methodName)) {
								continue;
							}

							content.append("@RequestMapping(\"/").append(methodName).append("\")\n");
							content.append(methodDecl.mods.toString()).append(" ");
							content.append(methodDecl.getReturnType().toString()).append(" ");
							content.append(methodName).append("(");
							String str = methodDecl.getParameters().toString();
							content.append(str).append("){").append("\n");
							content.append("return service.").append(methodName).append("(");
							methodDecl.getParameters().stream().forEach(jcVariableDecl -> {
								content.append(jcVariableDecl.name).append(",");
							});
							content.setCharAt(content.length()-1,')');
							content.append(";\n}").append("\n");

						}
					}
					content.append("}\n");


					processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING, "新代码:" + content);

					Writer writer = builderFile.openWriter();
					writer.append(content);
					writer.close();


				}
			} catch (IOException ioException) {
				ioException.printStackTrace();
				processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, ioException.getMessage());
				return false;
			} catch (Throwable exception) {
				processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, exception.getMessage());
				return false;
			}
		}

		return true;

	}


}
